package com.nekoneko.nekonekodemo.fragment;

import android.app.Activity;
import android.content.ContentResolver;
import android.content.ContentValues;
import android.content.res.Configuration;
import android.graphics.Color;
import android.graphics.ImageFormat;
import android.hardware.Camera;
import android.media.MediaRecorder;
import android.media.MediaScannerConnection;
import android.os.Bundle;
import android.os.CountDownTimer;
import android.os.Environment;
import android.provider.MediaStore;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.support.design.widget.TabLayout;
import android.support.v4.app.Fragment;
import android.support.v4.view.PagerAdapter;
import android.support.v4.view.ViewPager;
import android.util.DisplayMetrics;
import android.util.Log;
import android.util.SparseArray;
import android.util.SparseIntArray;
import android.view.Display;
import android.view.LayoutInflater;
import android.view.MotionEvent;
import android.view.Surface;
import android.view.SurfaceHolder;
import android.view.SurfaceView;
import android.view.View;
import android.view.ViewGroup;
import android.widget.RelativeLayout;

import com.nekoneko.nekonekodemo.R;
import com.nekoneko.nekonekodemo.ui.CircleProcessView;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

import butterknife.BindView;
import butterknife.ButterKnife;
import butterknife.Unbinder;

import static android.os.Environment.DIRECTORY_DOWNLOADS;

/**
 * 拍照 录制视频
 * Created by 想法的猫 on 2017/11/29 0029.
 */

public class CameraFragment extends Fragment implements SurfaceHolder.Callback, View.OnClickListener, View.OnTouchListener {
    Unbinder unbinder;
    @BindView(R.id.surface_view)
    SurfaceView surfaceView;
    MediaRecorder mediaRecorder;
    Camera camera;
    @BindView(R.id.tab_camera_mode_layout)
    TabLayout tabCameraModeLayout;
    @BindView(R.id.viewPage_camera_mode)
    ViewPager viewPageCameraMode;
    List<View> views = new ArrayList<>();
    String[] titles = {"拍照", "视频"};
    String photoPath;//拍照存储的地址
    String videoPath;//视频的地址
    final long VIDEO_DURATION = 10000;//视频时长 毫秒
    CountDownTimer countDownTimer;
    int[] previewSize = new int[2];

    @Nullable
    @Override
    public View onCreateView(LayoutInflater inflater, @Nullable ViewGroup container, @Nullable Bundle savedInstanceState) {
        View view = inflater.inflate(R.layout.frament_camera, container, false);
        unbinder = ButterKnife.bind(this, view);
        initView();
        return view;
    }

    private void initPhotoPath() {
        String dir = getContext().getExternalFilesDir(DIRECTORY_DOWNLOADS).getPath();
        photoPath = dir + File.separator + System.currentTimeMillis() + ".jpg";
    }

    private void initVideoPath() {
        String dir = getContext().getExternalFilesDir(DIRECTORY_DOWNLOADS).getPath();
        videoPath = dir + File.separator + System.currentTimeMillis() + ".mp4";
    }

    private void initView() {
        mediaRecorder = new MediaRecorder();
        SurfaceHolder mSurfaceHolder = surfaceView.getHolder();
        mSurfaceHolder.addCallback(this);
        initViewPager();
    }

    private int[] getScreenSize() {
        DisplayMetrics dm = getResources().getDisplayMetrics();
        int screenWidth = dm.widthPixels;
        int screenHeight = dm.heightPixels;
        Log.d("getScreenSize", "screenWidth=" + screenWidth + " screenHeight=" + screenHeight);
        return new int[]{screenWidth, screenHeight};
    }

    /**
     * 初始化viewPager
     */
    private void initViewPager() {
        View viewTakePhoto = LayoutInflater.from(getContext()).inflate(R.layout.view_camera_take_photo, (ViewGroup) getView(), false);
        viewTakePhoto.findViewById(R.id.view_take_photo).setOnClickListener(this);
        View viewRecordVideo = LayoutInflater.from(getContext()).inflate(R.layout.view_camera_record_video, (ViewGroup) getView(), false);
        CircleProcessView circleProcessView = viewRecordVideo.findViewById(R.id.processView);
        circleProcessView.setOnTouchListener(this);
        circleProcessView.setColor(Color.parseColor("#13B7F5"));
        circleProcessView.setPaintWidth(4);
        views.add(viewTakePhoto);
        views.add(viewRecordVideo);
        viewPageCameraMode.setAdapter(new ViewPagerAdapter());
        tabCameraModeLayout.setupWithViewPager(viewPageCameraMode);
    }

    /**
     * 从支持的previewSize中选择与目标size相近的
     *
     * @param supportedPreviewSizes
     * @param wantWidth
     * @param wantHeight
     * @return
     */
    private int[] getBestSize(List<Camera.Size> supportedPreviewSizes, int wantWidth, int wantHeight) {
        SparseArray<List<Camera.Size>> sparseIntArray = new SparseArray();
        int minWidthDValue = wantWidth;
        for (int i = 0; i < supportedPreviewSizes.size(); i++) {
            Camera.Size size = supportedPreviewSizes.get(i);
            int width = size.width;
            int widthDValue = Math.abs(width - wantWidth);
            minWidthDValue = widthDValue < minWidthDValue ? widthDValue : minWidthDValue;
            Log.d("getBestSize", "width=" + width + "  height=" + size.height + " widthDValue=" + widthDValue);
            List<Camera.Size> sizeList = sparseIntArray.get(widthDValue);
            if (sizeList == null) {
                sizeList = new ArrayList<>();
            }
            sizeList.add(size);
            sparseIntArray.put(widthDValue, sizeList);
        }

        int minHeightDValue = wantHeight;
        List<Camera.Size> sizeList = sparseIntArray.get(minWidthDValue);
        int[] resultSize = new int[2];//
        for (int i = 0; i < sizeList.size(); i++) {
            Camera.Size size = sizeList.get(i);
            resultSize[0] = size.width;
            int height = size.height;
            int dValue = Math.abs(height - wantHeight);
            if (minHeightDValue > dValue) {
                minHeightDValue = dValue;
                resultSize[1] = height;
            }
        }
        Log.d("getBestSize", "resultHeight=" + resultSize[0] + " resultHeight=" + resultSize[1]);
        return resultSize;
    }


    private void startPreView(SurfaceHolder holder) {
        camera = camera == null ? Camera.open(Camera.CameraInfo.CAMERA_FACING_BACK) : camera;
        setCameraDisplayOrientation(getActivity(), Camera.CameraInfo.CAMERA_FACING_BACK, camera);
        mediaRecorder = mediaRecorder == null ? new MediaRecorder() : mediaRecorder;
        try {
            camera.setPreviewDisplay(holder);
            Camera.Parameters parameters = camera.getParameters();
            //设置图片格式
            parameters.setPictureFormat(ImageFormat.JPEG);
            //设置图片的质量
            parameters.set("jpeg-quality", 100);
            List<Camera.Size> supportedPreviewSizes = parameters.getSupportedPreviewSizes();
            previewSize = getBestSize(supportedPreviewSizes, 1280, 720);
            parameters.setPreviewSize(previewSize[0], previewSize[1]);
            //768 1024
            int[] screenSize = getScreenSize();
            //1280/720 768 1024(竖屏)
            float n = (float) previewSize[0] / previewSize[1];//视频高度 铺满屏幕 计算出对应的屏幕宽度
            float surfaceWidth = screenSize[1] / n;//1024
            float surfaceHeight = screenSize[0] * n;//768
            Log.d("startPreView", "surfaceWidth=" + surfaceWidth + "surfaceHeight=" + surfaceHeight);
            //如果缩放所得的预览宽小于屏幕宽 则以铺满宽度为前提
            if (screenSize[0] - surfaceWidth >= 0) {
                surfaceHeight = screenSize[0] / surfaceWidth * screenSize[1];
            }
            Log.d("startPreView", "surfaceWidth=" + surfaceWidth + "surfaceHeight=" + surfaceHeight);
            float marinTotal = surfaceHeight - screenSize[1];
            RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) surfaceView.getLayoutParams();
            int margin = (int) (marinTotal / 2);
            layoutParams.setMargins(0, -margin, 0, -margin);
            surfaceView.setLayoutParams(layoutParams);
            //实现Camera自动对
            List<String> focusModes = parameters.getSupportedFocusModes();
            if (focusModes != null) {
                for (String mode : focusModes) {
                    if (mode.contains("continuous-video")) {
                        parameters.setFocusMode("continuous-video");
                    }
                }
            }
            camera.setDisplayOrientation(90);
            camera.setParameters(parameters);
            camera.startPreview();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    @Override
    public void onDestroyView() {
        super.onDestroyView();
        unbinder.unbind();
    }

    @Override
    public void surfaceCreated(SurfaceHolder surfaceHolder) {
        startPreView(surfaceHolder);
    }

    @Override
    public void surfaceChanged(SurfaceHolder surfaceHolder, int i, int i1, int i2) {

    }

    @Override
    public void surfaceDestroyed(SurfaceHolder surfaceHolder) {
        if (camera != null) {
            //停止预览并释放摄像头资源
            camera.stopPreview();
            camera.release();
            camera = null;
        }
        if (mediaRecorder != null) {
            mediaRecorder.release();
            mediaRecorder = null;
        }
    }

    @Override
    public void onClick(View view) {
        switch (view.getId()) {
            case R.id.view_take_photo://拍照
                takePhoto();
                break;
        }
    }

    /**
     * 拍照
     */
    private void takePhoto() {
        camera.takePicture(new Camera.ShutterCallback() {
            @Override
            public void onShutter() {

            }
        }, null, null, new Camera.PictureCallback() {
            @Override
            public void onPictureTaken(byte[] bytes, Camera camera) {
                onTakePhoto(bytes);
            }
        });
    }

    /**
     * 拍照之后保存图片
     *
     * @param data
     */
    private void onTakePhoto(byte[] data) {
        initPhotoPath();
        FileOutputStream fos = null;
        try {
            new File(photoPath).createNewFile();
            fos = new FileOutputStream(photoPath);
            fos.write(data);
            fos.flush();
            String picName = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
            ContentValues values = new ContentValues();
            ContentResolver resolver = getActivity().getContentResolver();
            values.put(MediaStore.Images.ImageColumns.DATE_TAKEN, System.currentTimeMillis());
            values.put(MediaStore.Images.ImageColumns.DATE_ADDED, System.currentTimeMillis() / 1000);
            values.put(MediaStore.Images.ImageColumns.DATE_MODIFIED, System.currentTimeMillis() / 1000);
            values.put(MediaStore.Images.ImageColumns.DATA, photoPath);
            values.put(MediaStore.Images.ImageColumns.TITLE, picName);
            values.put(MediaStore.Images.ImageColumns.DISPLAY_NAME, "照片");
            values.put(MediaStore.Images.ImageColumns.ORIENTATION, 90);
            resolver.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
            MediaScannerConnection.scanFile(getContext(), new String[]{Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).getPath() + File.separator + picName}, null, null);
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (fos != null) {
                    fos.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }

    @Override
    public boolean onTouch(final View view, MotionEvent motionEvent) {
        Log.d("motionEvent", "motionEvent=" + motionEvent.getAction());
        switch (motionEvent.getAction()) {
            case MotionEvent.ACTION_DOWN:
                startRecord();
                countDownTimer = new CountDownTimer(VIDEO_DURATION, 100) {
                    @Override
                    public void onTick(long l) {
                        int percent = (int) ((VIDEO_DURATION - l) * 100 / VIDEO_DURATION);
                        CircleProcessView circleProcessView = (CircleProcessView) view;
                        circleProcessView.updateProcess(percent);
                    }

                    @Override
                    public void onFinish() {
                        CircleProcessView circleProcessView = (CircleProcessView) view;
                        circleProcessView.updateProcess(100);
                        Log.d("countDownTimer", "onFinish");
                        stopRecordSave();
                    }
                };
                countDownTimer.start();
                break;
            case MotionEvent.ACTION_CANCEL:
            case MotionEvent.ACTION_UP:
                stopRecordSave();
                countDownTimer.cancel();
                break;
        }
        return true;
    }

    /**
     * 开始录制
     */
    private void startRecord() {
        if (mediaRecorder != null) {
            //没有外置存储, 直接停止录制
            if (!Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
                return;
            }
            mediaRecorder.reset();
            camera.stopPreview();
            camera.unlock();
            mediaRecorder.setCamera(camera);
            //从相机采集视频
            mediaRecorder.setVideoSource(MediaRecorder.VideoSource.CAMERA);
            // 从麦克采集音频信息
            mediaRecorder.setAudioSource(MediaRecorder.AudioSource.MIC);
            // TODO: 2016/10/20  设置视频格式
            mediaRecorder.setOutputFormat(MediaRecorder.OutputFormat.MPEG_4);
            //每秒的帧数
            //编码格式
            mediaRecorder.setVideoEncoder(MediaRecorder.VideoEncoder.H264);
            mediaRecorder.setAudioEncoder(MediaRecorder.AudioEncoder.AMR_NB);
            // 设置帧频率，然后就清晰了
            mediaRecorder.setVideoEncodingBitRate(1024 * 1024);
            mediaRecorder.setAudioSamplingRate(8000);
            mediaRecorder.setVideoSize(previewSize[0], previewSize[1]);// 设置分辨率
            initVideoPath();
            File mTargetFile = new File(videoPath);
            if (!mTargetFile.exists()) {
                try {
                    mTargetFile.createNewFile();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
            mediaRecorder.setOutputFile(mTargetFile.getAbsolutePath());
            mediaRecorder.setPreviewDisplay(surfaceView.getHolder().getSurface());
            //解决录制视频, 播放器横向问题
            mediaRecorder.setOrientationHint(getDegreesResult(getActivity(), Camera.CameraInfo.CAMERA_FACING_BACK));
            try {
                mediaRecorder.prepare();
            } catch (IOException e) {
                e.printStackTrace();
            }
            //正式录制
            mediaRecorder.start();
        }
    }


    /**
     * 停止录制 并且保存
     */
    private void stopRecordSave() {
        try {
            mediaRecorder.stop();
            String picName = new SimpleDateFormat("yyyyMMdd_HHmmss").format(new Date());
            ContentValues values = new ContentValues();
            ContentResolver resolver = getActivity().getContentResolver();
            values.put(MediaStore.Video.VideoColumns.DATE_TAKEN, System.currentTimeMillis());
            values.put(MediaStore.Video.VideoColumns.DATE_ADDED, System.currentTimeMillis() / 1000);
            values.put(MediaStore.Video.VideoColumns.DATE_MODIFIED, System.currentTimeMillis() / 1000);
            values.put(MediaStore.Video.VideoColumns.DATA, videoPath);
            values.put(MediaStore.Video.VideoColumns.TITLE, picName);
            values.put(MediaStore.Video.VideoColumns.DISPLAY_NAME, "视频");
            resolver.insert(MediaStore.Video.Media.EXTERNAL_CONTENT_URI, values);
            MediaScannerConnection.scanFile(getContext(), new String[]{Environment.getExternalStoragePublicDirectory(Environment.DIRECTORY_DCIM).getPath() + File.separator + picName}, null, null);

        } catch (Exception ex) {

        }

    }

    /**
     * 停止录制, 不保存
     */
    private void stopRecordUnSave() {
        mediaRecorder.stop();
        File videoFile = new File(videoPath);
        if (videoFile.exists()) {
            videoFile.delete();
        }
    }

    /**
     * 拍照、录制视频的viewPager
     */
    class ViewPagerAdapter extends PagerAdapter {
        @Override
        public int getCount() {
            return views.size();
        }

        @Override
        public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
            container.removeView(views.get(position));
        }

        @Nullable
        @Override
        public CharSequence getPageTitle(int position) {
            return titles[position];
        }

        @NonNull
        @Override
        public Object instantiateItem(@NonNull ViewGroup container, int position) {
            View view = views.get(position);
            container.addView(view);
            return view;
        }

        @Override
        public boolean isViewFromObject(@NonNull View view, @NonNull Object object) {
            return view == object;
        }
    }

    //If you want to make the camera image show in the same orientation as the display, you can use the following code.
    public static void setCameraDisplayOrientation(Activity activity, int cameraId, android.hardware.Camera camera) {
        int result = getDegreesResult(activity, cameraId);
        camera.setDisplayOrientation(result);
    }

    private static int getDegreesResult(Activity activity, int cameraId) {
        //通过相机ID获得相机信息
        Camera.CameraInfo info = new Camera.CameraInfo();
        Camera.getCameraInfo(cameraId, info);

        //获得当前屏幕方向
        int rotation = activity.getWindowManager().getDefaultDisplay().getRotation();
        int degrees = 0;
        Log.d("CameraOrientation", "rotation=" + rotation);
        switch (rotation) {
            //若屏幕方向与水平轴负方向的夹角为0度
            case Surface.ROTATION_0:
                degrees = 0;
                break;
            //若屏幕方向与水平轴负方向的夹角为90度
            case Surface.ROTATION_90:
                degrees = 90;
                break;
            //若屏幕方向与水平轴负方向的夹角为180度
            case Surface.ROTATION_180:
                degrees = 180;
                break;
            //若屏幕方向与水平轴负方向的夹角为270度
            case Surface.ROTATION_270:
                degrees = 270;
                break;
        }
        int result;
        if (info.facing == Camera.CameraInfo.CAMERA_FACING_FRONT) {
            //前置摄像头作镜像翻转
            result = (info.orientation + degrees) % 360;
            result = (360 - result) % 360;  // compensate the mirror
        } else {  // back-facing
            result = (info.orientation - degrees + 360) % 360;
        }
        return result;
    }
}
